import { classNameDeal, dom } from "../tool";

interface MarkType {
    scale: number;
    text: string;
}

interface PropType {
    min?: number;
    max?: number;
    step?: number;
    value?: number;
    onChange?: (value: number | null) => void;
    marks?: MarkType[];
    disabled?: boolean;
    vertical?: boolean;
    size?: number;
    hidden?: boolean;
    style?: string;
}

interface SlideType<PropType> {
    new(props?: PropType): SlideType<PropType>;
    value: number | null;
    disabled: boolean;
    setDisabled: (disabled: boolean) => void;
    setValue: (value: number | null | undefined) => void;
    render: (node?: HTMLElement) => HTMLElement;
    hidden: boolean;
    setHidden: (arg: boolean) => void;
    onChange?: (value: number | null) => void;
}

function Slide(this: SlideType<PropType>, props: PropType = {}) {
    const { min = 0, max = 100, value = 0, onChange, disabled = false, step = 1, vertical = false, size = 4, hidden = false, style="" } = props;
    this.onChange = onChange;
    const dmax = max - min;
    const padding = 8;
    const slideLine = dom('div', { className: 'gkh-line' });
    const slide = dom('div', { className: 'gkh-slide' });
    const line = dom('div', { className: 'gkh-line' });
    const container = dom('div', {
        className: disabled ? 'gkh-slide-box gkh-disabled' : 'gkh-slide-box',
        style: style.concat(hidden ? "visibility:hidden;" : ""),
        childs: [
            line,
            slideLine,
            slide
        ]
    });

    if (vertical) {
        container.style.width = String(2 * padding + size).concat("px");
        container.style.height = "100%";
        line.style.left = String(padding).concat("px");
        line.style.width = String(size).concat("px");
        line.style.height = "calc(100% - 20px)";
        line.style.top = "10px";
        slideLine.style.left = String(padding).concat("px");
        slideLine.style.width = String(size).concat("px");
        slideLine.style.height = "0";
        slideLine.style.top = "10px";
        slide.style.left = String((2 * padding + size - 12) / 2).concat("px");
    } else {
        container.style.height = String(2 * padding + size).concat("px");
        container.style.width = "100%";
        line.style.top = String(padding).concat("px");
        line.style.height = String(size).concat("px");
        line.style.width = "calc(100% - 20px)";
        line.style.left = "10px";
        slideLine.style.top = String(padding).concat("px");
        slideLine.style.height = String(size).concat("px");
        slideLine.style.width = "0";
        slideLine.style.left = "10px";
        slide.style.top = String((2 * padding + size - 12) / 2).concat("px");
    }

    let hasDown = false;
    let length = '';
    let preValue = value;
    let temp = value;
    let lineInfo: any = {};
    const endSlide = (event: any) => {
        if (hasDown) {
            if (vertical) {
                temp = min + (window.screenY + event.clientY - lineInfo.y) * dmax / lineInfo.height;
            } else {
                temp = min + (window.screenX + event.clientX - lineInfo.x) * dmax / lineInfo.width;
            }
            if (Math.abs(temp - preValue) > step) {
                preValue = temp;
                this.setValue(temp);
                if (onChange) {
                    onChange(this.value);
                }
            }
        }
        hasDown = false;
        container.onmousemove = null;
        document.removeEventListener('mouseup', endSlide);
    }
    const mouseMove = (event: any) => {
        if (event.stopPropagation) {
            event.stopPropagation();
        }
        else {
            event.cancelBubble = true;
        }
        if (hasDown) {
            if (vertical) {
                temp = min + (window.screenY + event.clientY - lineInfo.y) * dmax / lineInfo.height;
            } else {
                temp = min + (window.screenX + event.clientX - lineInfo.x) * dmax / lineInfo.width;
            }
            if (Math.abs(temp - preValue) > step) {
                preValue = temp;
                this.setValue(temp);
                if (this.onChange) {
                    this.onChange(this.value);
                }
            }
        }
    }
    container.onmousedown = (event: any) => {
        hasDown = true;
        lineInfo = line.getBoundingClientRect();
        if (event.stopPropagation) {
            event.stopPropagation();
        }
        else {
            event.cancelBubble = true;
        }
        if (vertical) {
            temp = min + (window.screenY + event.clientY - lineInfo.y) * dmax / lineInfo.height;
        } else {
            temp = min + (window.screenX + event.clientX - lineInfo.x) * dmax / lineInfo.width;
        }
        if (Math.abs(temp - preValue) > step) {
            preValue = temp;
            this.setValue(temp);
            if (this.onChange) {
                this.onChange(this.value);
            }
        }
        container.onmousemove = mouseMove;
        document.addEventListener('mouseup', endSlide);
    }

    this.hidden = hidden;
    this.setHidden = (arg) => {
        this.hidden = arg;
        container.style.visibility = arg ? 'hidden' : 'visible';
    }
    this.disabled = disabled;
    this.setDisabled = (arg) => {
        this.disabled = arg;
        container.setAttribute('class', classNameDeal(container.getAttribute('class') || '', "gkh-disabled", arg ? 'add' : 'del'));
    }
    this.setValue = (arg) => {
        if (arg == null || arg == undefined) {
            this.value = null;
            if (vertical) {
                slideLine.style.height = "0px";
                slide.style.bottom = "0";
            } else {
                slideLine.style.width = "0px";
                slide.style.left = "0";
            }
        } else if (arg >= min && arg <= max) {
            this.value = arg;
            if (vertical) {
                length = String(line.offsetHeight * (arg - min) / dmax).concat('px');
                slideLine.style.height = length;
                slide.style.bottom = length;
            } else {
                length = String(line.offsetWidth * (arg - min) / dmax).concat('px');
                slideLine.style.width = length;
                slide.style.left = length;
            }
        }
    }
    this.setValue(value);
    this.render = (node) => {
        if (node) {
            node.appendChild(container);
            this.setValue(this.value);
        }
        return container;
    }
    return this;
}
export default Slide as unknown as SlideType<PropType>;